<?php
/*-------------------------------------------------------------------------\
|
|  ========================================================
|  Fusion Registry GPL
|  Copyright (C) 2007 Fusion Scripts
|
|  This program is free software; you can redistribute it and/or
|  modify it under the terms of the GNU General Public License
|  as published by the Free Software Foundation; either version 2
|  of the License, or (at your option) any later version.
|
|  This program is distributed in the hope that it will be useful,
|  but WITHOUT ANY WARRANTY; without even the implied warranty of
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|  GNU General Public License for more details.
|
|  You should have received a copy of the GNU General Public License
|  along with this program; if not, write to the Free Software
|  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
|  ========================================================
|
|  Email: info@fusionscripts.com
|  Web-Site: http://www.fusionscripts.com/
|
|  $Id: main.php 4 2008-08-03 01:43:03Z registry.fusion $
|
\-------------------------------------------------------------------------*/

/**
 * 'main' class for the Fusion Registry.
 *
 * @package Fusion Registry
 * @version $Id: main.php 4 2008-08-03 01:43:03Z registry.fusion $
 */

/**
 * Fusion Registry core require
 */
require_once(REGISTRY_PATH.'/lib/core.php');

/**
 * Class 'registry_main' is in charge of the main menu, browsing, and searching.
 *
 * This class should be invoked by the parent integration harness.
 * Most functions of this class do not have return values, instead the
 * redirect function is called to print a pretty thank you message to the
 * end user and stops the procedural code.
 *
 * @package Fusion Registry
 */
class registry_main
{
    var $ipsclass;

    /**#@+ @var string */
    var $output     = "";
    var $page_title = "";
    /**#@-*/

    /**#@+ @var array */
    var $data          = array();
    var $site_bits     = array();
    var $registry_config = array();
    var $nav_bar       = array();
    var $html          = array( 'core', 'main', 'gallery', 'item' );
    var $lib           = array( 'custom_fields', 'content', 'functions', 'attach' );
    /**#@-*/

    /** @var object Fusion Registry core */
    var $core = "";

    /**
     * Invoked from parent harness, this executes the code.
     *
     * This is the only function which should be called from the harness.
     * This function is the traffic cop for this class, it should
     * do very little procedural code, if any.
     *
     * @param string $param Function to call
     */
    function auto_run($param='')
    {
        // Initialize core
        $this->core = new registry_core();
        $this->core->ipsclass =& $this->ipsclass;
        $this->core->auto_run(&$this);

        // Start our Nav Bar
        $this->nav_bar[] = "<a href='{$this->ipsclass->base_url}autocom=".REGISTRY_URL."'>".$this->ipsclass->lang['title']."</a>";

        // Which way to go?
        switch( $param )
        {
            case 'browse':
                $this->data['body'] = $this->browse();
                break;

            case 'do_member_search':
                $this->data['body'] = $this->do_member_search();
                break;

            case 'do_search':
                $this->data['body'] = $this->do_search();
                break;

            case 'search_menu':
                $this->data['body'] = $this->search_menu();
                break;

            case 'stats':
                $this->data['body'] = $this->stats();
                break;

            case 'main_menu':
            default:
                $this->data['body'] = $this->main_menu();
                break;
        }

        // Let's create the common output elements now
        $this->data['navigation']     = $this->lib['functions']->do_navigation();
        $this->data['latest_updated'] = $this->lib['functions']->do_latest_updated();
        $this->data['my_cars']        = $this->lib['functions']->do_my_items();

        // Print it all out
        $this->output = $this->core->process_output();

        // Template Replacements
        foreach( $this->site_bits as $k => $v )
        {
            $this->output = str_replace( "<!--R.TEMPLATE.".strtoupper($k)."-->", $v, $this->output );
        }

        $this->ipsclass->print->add_output( $this->output );

        // Shall we use our Custom page title, or the default one?
        $this->page_title = empty($this->page_title) ? $this->ipsclass->lang['page_title'] : $this->page_title;

        // Set the title and nav bar, print the output
        $this->ipsclass->print->do_output( array( 'TITLE' => $this->ipsclass->vars['board_name'] .' -> '. $this->page_title,
                                                  'NAV'   => $this->nav_bar ) );
    }


    /**
     * Browsing the Fusion Registry
     *
     * This is a lot like browsing a forum, has controls for sorting by column
     * and direction. The {@link do_search} function feeds into this function as well.
     * If we are sent the 'search=1' flag, this function will look at the session
     * variable search_result which contains the already filtered master set of
     * item_id's that were searched for. It is important to note that this function
     * doesn't do any of the searching, it mearly reduces the master browsing list
     * to the already compiled search which is stored in the session variable.
     *
     * @param integer $bypass Set to true to bypass the error conditions
     * @return string Success returns template 'browse'; Failure returns template 'message'
     */
    function browse( $bypass = 0 )
    {
        // Do they have permission to browse?
        if ( $this->ipsclass->check_perms($this->registry_config['browse_perms']) != TRUE )
        {
            if ( $bypass == 0 )
            {
                $this->ipsclass->Error( array( LEVEL => 1, MSG => 'no_permission') );
            }
            else
            {
                return;
            }
        }

        $data = array ();

        $sort_key = $this->ipsclass->select_var( array( 1 => $this->ipsclass->input['sort_key'],
                                                        2 => $this->forum['sort_key'],
                                                        3 => 'date_updated'
                                               )      );

        $sort_by = $this->ipsclass->select_var( array( 1 => $this->ipsclass->input['sort_by'],
                                                       2 => $this->forum['sort_order'] ,
                                                       3 => 'Z-A'
                                              )      );

        $First = $this->ipsclass->select_var( array( 1 => intval($this->ipsclass->input['st']),
                                                     2 => 0
                                            )      );

        $sort_keys = array( 'date_created' => 'sort_by_date_created',
                            'date_updated' => 'sort_by_date_updated',
                            'name'         => 'sort_by_member',
                            'views'        => 'sort_by_views',
                            'total_mods'   => 'sort_by_mods',
                          );

        $sort_by_keys = array( 'Z-A'  => 'descending_order',
                               'A-Z'  => 'ascending_order',
                             );

        // check for any form funny business by wanna-be hackers
        if ( !isset($sort_keys[$sort_key]) and !isset($sort_by_keys[$sort_by]) )
        {
            if ( $bypass == 0 )
            {
                $this->ipsclass->Error( array( LEVEL => 5, MSG =>'incorrect_use' ) );
            }
            else
            {
                return;
            }
        }

        $r_sort_by = $sort_by == 'A-Z' ? 'ASC' : 'DESC';

        // Count the result set.
        $sql = "SELECT COUNT(g.id) as max FROM ibf_registry_items AS g LEFT JOIN ibf_members AS m ON g.member_id = m.id ";

        $additional_where = '';
        $data['hidden_elements'] = '';
        $data['search_results_explain'] = '';

        if ( $this->ipsclass->input['search'] == 1 )
        {
            // Are we allowed to search?
            if (! $this->ipsclass->vars['allow_search'])
            {
                $this->ipsclass->Error( array( LEVEL => 1, MSG => 'search_off') );
            }

            // Are we really allowed to search?
            if ($this->ipsclass->member['g_use_search'] != 1)
            {
                $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_permission' ) );
            }

            // Add the search data set restriction
            $search_result = $this->lib['session']->get_session_var('search_result');

            // If we don't have any search results we need to let the end user know
            if ( is_array($search_result) AND !empty($search_result) )
            {
                // First let's typecast all to int's just incase
                $safe_search_result = array();

                foreach ( $search_result as $item_id )
                {
                    array_push($safe_search_result, intval($item_id));
                }

                // And then we polish this off by creating our SQL syntax
                $search_set = join("','", $safe_search_result);

                $search_set = "('". $search_set ."')";

                $sql .= " WHERE g.id IN $search_set ";
                $additional_where .= " AND g.id IN $search_set";

                // Add the hidden elements for the form
                $data['hidden_elements'] .= "<input type='hidden' name='search' value='1' />\n";

                // Add the search description
                $data['search_results_explain'] = $this->ipsclass->compiled_templates['skin_registry_main']->search_results_explain();
            }
            else
            {
                $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_search_results' ) );
            }
        }
        // Execute the count query
        $this->ipsclass->DB->query($sql);

        $total_possible = $this->ipsclass->DB->fetch_row();

        // Generate the forum page span links
        $data['SHOW_PAGES'] = $this->ipsclass->build_pagelinks( array( 'TOTAL_POSS'  => $total_possible['max'],
                                                                       'PER_PAGE'    => $this->registry_config['cars_per_page'],
                                                                       'CUR_ST_VAL'  => $this->ipsclass->input['st'],
                                                                       'L_SINGLE'    => $this->ipsclass->lang['single_page_garage'],
                                                                       'L_MULTI'     => $this->ipsclass->lang['multi_page_garage'],
                                                                       'BASE_URL'    => $this->base_url."?autocom=".REGISTRY_URL."&amp;cmd=browse&amp;sort_by=$sort_by&amp;sort_key=$sort_key&amp;search=".$this->ipsclass->input['search'],
                                                              )      );

        // Get our custom fields to be shown on the browse screen, if any
        $cf_defs = $this->lib['custom_fields']->get_cf_defs( array('WHERE' => "field_browse='1'", 'ORDER BY' => 'field_order ASC') );

        // Create our sql id list, this will be used when retrieving the custom field entries
        $cf_ids = "'". implode( "','", array_keys($cf_defs) ) . "'";


        // Build our <th>'s for the custom fields
        $data['custom_field_th'] = '';

        // How much width should each get? We're going to be nice and share equally :)
        //   48% is the amount left over from the static columns.
        $denom = count($cf_defs) ? count($cf_defs) : 1;
        $cf_width = 48 / $denom;
        $cf_width .= '%';

        // Loop through each one and add the <th> html to the output
        foreach ( $cf_defs as $cf_id => $cf_row )
        {
            $cf_data['field_name'] = $cf_row['field_name'];
            $cf_data['field_width'] = $cf_width;

            $data['custom_field_th'] .= $this->ipsclass->compiled_templates['skin_registry_main']->browse_th($cf_data);
        }


        // Start building the query for the garage
        $query = "SELECT g.id, g.image_id, g.member_id, g.views, g.date_updated,
                    g.date_created, m.members_display_name, count(mods.id) AS total_mods
                  FROM ( ibf_members AS m, ibf_registry_items AS g )
                    LEFT JOIN ibf_registry_mods AS mods ON mods.item_id = g.id
                  WHERE g.member_id = m.id ". $additional_where ."
                  GROUP BY g.id";

        // Finish off the query
        $First = $First ? $First : 0;

        $query .= " ORDER BY $sort_key $r_sort_by LIMIT $First,". $this->registry_config['cars_per_page'];

        $outer_resource = $this->ipsclass->DB->query($query);

        // Print each item/row in the garage
        $total_cars_printed = 0;

        while ( $row = $this->ipsclass->DB->fetch_row($outer_resource) )
        {
            // Get our custom fields data
            $cf_entries = $this->lib['custom_fields']->get_cf_entries( array( 'WHERE' => "item_id='".$row['id']."' AND field_id IN (".$cf_ids.")" ) );

            // Build our <td>'s for the custom fields
            $row['custom_fields'] = '';

            foreach ( $cf_defs as $cf_id => $cf_row )
            {
                // Which css class should we be? This isn't perfect, but will have to do.
                $cf_data['field_class'] = $total_cars_printed % 2 ? 'row2' : 'row1';

                $cf_data['item_id'] = $row['id'];

                $cf_data['field_value'] = $this->lib['custom_fields']->process_cf_value( array( 'def' => $cf_row,
                                                                                                'value' => $cf_entries[$cf_id]['field_value'],
                                                                                                'type' => 'view',
                                                                                       )      );

                $row['custom_fields'] .= $this->ipsclass->compiled_templates['skin_registry_main']->browse_td($cf_data);
            }

            // Make the dates human readable
            // Change time to human readable format
            $row['date_updated'] = gmdate( $this->registry_config['date_format'], $row['date_updated'] + $this->ipsclass->get_time_offset() );
            $row['date_created'] = gmdate( $this->registry_config['date_format'], $row['date_created'] + $this->ipsclass->get_time_offset() );

            // If we have an attached image, give it an icon
            if ( !empty($row['image_id']) )
            {
                $row['icon'] = '<{R_PHOTO}>';
            }

            $data['REGISTRY_ROWS'] .= $this->ipsclass->compiled_templates['skin_registry_main']->browse_row($row);

            $total_cars_printed++;
        }

        // Finish off the rest of the page
        $this->ipsclass->lang['showing_text'] = preg_replace( "/<#MATCHED_CARS#>/", $total_cars_printed    , $this->ipsclass->lang['showing_text'] );
        $this->ipsclass->lang['showing_text'] = preg_replace( "/<#TOTAL_CARS#>/"  , $total_possible['max'] , $this->ipsclass->lang['showing_text'] );

        $sort_key_html  = "<select name='sort_key'  class='forminput'>\n";
        $sort_by_html   = "<select name='sort_by'   class='forminput'>\n";

        foreach ($sort_by_keys as $k => $v)
        {
            $sort_by_html .= $k == $sort_by ? "<option value='$k' selected='selected'>". $this->ipsclass->lang[ $sort_by_keys[$k] ] ."</option>\n"
                                            : "<option value='$k'>". $this->ipsclass->lang[ $sort_by_keys[$k] ] ."</option>\n";
        }

        foreach ($sort_keys as  $k => $v)
        {
            $sort_key_html .= $k == $sort_key ? "<option value='$k' selected='selected'>". $this->ipsclass->lang[ $sort_keys[$k] ] ."</option>\n"
                                              : "<option value='$k'>". $this->ipsclass->lang[ $sort_keys[$k] ] ."</option>\n";
        }

        $this->ipsclass->lang['sort_text'] = preg_replace( "!<#SORT_KEY_HTML#>!", "$sort_key_html</select>", $this->ipsclass->lang['sort_text'] );
        $this->ipsclass->lang['sort_text'] = preg_replace( "!<#ORDER_HTML#>!", "$sort_by_html</select>", $this->ipsclass->lang['sort_text'] );

        // Only do these last few steps if not bypassed
        if ( $bypass == 0 )
        {
            // Set page title
            $this->page_title = $this->ipsclass->lang['browse'].' '.$this->ipsclass->lang['title'];

            // Add to our Nav Bar
            $this->nav_bar[] = "<a href='{$this->ipsclass->base_url}autocom=".REGISTRY_URL."&amp;cmd=browse'>{$this->ipsclass->lang['browse']}</a>";
        }

        return $this->ipsclass->compiled_templates['skin_registry_main']->browse($data);
    }


    /**
     * Search the registry by member name
     *
     * This function will do the hard job of actually searching the registry.
     * It will produce a result set of item_id's that will be stored into the
     * session variables. Then we redirect to the {@link browse} function and
     * set the 'search=1' flag. That flag will alert the {@link browse} function
     * to attempt to use the result set found in the session.
     *
     * @return string Failure returns template 'message'
     */
    function do_member_search()
    {
        // Do they have permission?
        if ( ($this->ipsclass->check_perms($this->registry_config['interact_perms']) != TRUE) )
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'no_permission') );
        }

        // Are we allowed to search?
        if (! $this->ipsclass->vars['allow_search'])
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'search_off') );
        }

        // Are we really allowed to search?
        if ($this->ipsclass->member['g_use_search'] != 1)
        {
            $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_permission' ) );
        }

        // We are going to prepare the list of item_id's and store them in the session
        // data. This will cut down on having to run this search for browsing through
        // the results.
        $this->ipsclass->DB->query("SELECT items.id FROM ibf_registry_items AS items ".
                                        "LEFT JOIN ibf_members AS m ON items.member_id = m.id ".
                                   "WHERE m.members_display_name = '".$this->ipsclass->input['member_name']."'");

        if ( $this->ipsclass->DB->get_num_rows() > 0 )
        {
            $result_ids = array();

            // Create our stack of result ids
            while( $row = $this->ipsclass->DB->fetch_row() )
            {
                array_push( $result_ids, $row['id'] );
            }

            // Cram the result set into the session data
            $this->lib['session']->set_session_var( array( 'search_result' => $result_ids ) );

            $this->ipsclass->print->redirect_screen( $this->ipsclass->lang['search_complete'], "autocom=".REGISTRY_URL."&amp;cmd=browse&amp;search=1" );
        }
        else
        {
            // Sorry bud, no results :(
            $this->lib['session']->set_session_var( array( 'search_result' => array() ) );

            $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_search_results' ) );
        }
    }


    /**
     * Dynamic search of the registry
     *
     * This function will do the hard job of actually searching the registry.
     * It will produce a result set of item_id's that will be stored into the
     * session variables. Then we redirect to the {@link browse} function and
     * set the 'search=1' flag. That flag will alert the {@link browse} function
     * to attempt to use the result set found in the session.
     *
     * @return string Failure returns template 'message'
     */
    function do_search()
    {
        // Do they have permission?
        if ( ($this->ipsclass->check_perms($this->registry_config['interact_perms']) != TRUE) )
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'no_permission') );
        }

        // Are we allowed to search?
        if (! $this->ipsclass->vars['allow_search'])
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'search_off') );
        }

        // Are we really allowed to search?
        if ($this->ipsclass->member['g_use_search'] != 1)
        {
            $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_permission' ) );
        }

        // Grab all the defs that are searchable first
        $cf_defs = $this->lib['custom_fields']->get_cf_defs( array( 'WHERE' => "field_search='1'" ) );

        // Process the custom fields input
        $cf_input = $this->lib['custom_fields']->process_cf_input($cf_defs);

        // Here comes the tricky part, we need to loop through and dynamically create
        // our SQL statement for the search, hold on to your hats

        // Keep track of field_id's for our 'AND' logic, if used
        $searched_fields = array();

        $where_sql = ' WHERE ';

        foreach ( $cf_defs as $cf_id => $cf_row )
        {
            // Did they enter a keyword for this field, and did they choose this field?
            if ( !empty($cf_input[$cf_id]) AND $this->ipsclass->input['search_' . $cf_id] == 1 )
            {
                $where_sql .= " ( field_id = '$cf_id' AND field_value LIKE '%$cf_input[$cf_id]%' ) OR ";

                // This will be used later in our 'AND' logic
                if ( $this->ipsclass->input['search_logic'] == 'AND' )
                {
                    array_push( $searched_fields, $cf_id );
                }
            }
        }

        // Strip off last 'OR'
        $where_sql = substr($where_sql, 0, -3);

        // We are going to prepare the list of item_id's and store them in the session
        // data. This will cut down on having to run this search for browsing through
        // the results.

        // SQL select is a little different depending on logic, since we need to post
        //   process 'AND' we don't want sql to filter distinct item_id's.
        if ( $this->ipsclass->input['search_logic'] == 'AND' )
        {
            $select_sql = "item_id, field_id";
        }
        else
        {
            $select_sql = "distinct(item_id)";
        }

        $this->ipsclass->DB->query("SELECT $select_sql FROM ibf_registry_field_entries $where_sql");

        if ( $this->ipsclass->DB->get_num_rows() > 0 )
        {
            $result_ids = array();

            // Post process if they are doing 'AND' logic. Couldn't come up with a way to have
            //   sql do this for us, may change this in the future.
            if ( $this->ipsclass->input['search_logic'] == 'AND' )
            {
                $result_catalog = array();

                // First build our catalog of all the fields found for each item
                while( $row = $this->ipsclass->DB->fetch_row() )
                {
                    $result_catalog[ $row['item_id'] ][ $row['field_id'] ] = TRUE;
                }

                // Now determine which items have all the fields that were searched for.
                // This is our 'AND' logic at work.
                foreach ( $result_catalog as $item_id => $item_array )
                {
                    // Start the flag true
                    $match = TRUE;

                    // Loop through all the searched fields and see if it was found
                    foreach ( $searched_fields as $field_id )
                    {
                        if ( $result_catalog[ $item_id ][ $field_id ] != TRUE )
                        {
                            $match = FALSE;

                            continue;
                        }
                    }

                    // If it passed all the required matches, then we got a match!
                    if ( $match === TRUE )
                    {
                        array_push( $result_ids, $item_id );
                    }
                }
            }
            else
            {
                // Default to 'OR' logic
                while( $row = $this->ipsclass->DB->fetch_row() )
                {
                    array_push( $result_ids, $row['item_id'] );
                }
            }

            // Cram the result set into the session data
            $this->lib['session']->set_session_var( array( 'search_result' => $result_ids ) );

            $this->ipsclass->print->redirect_screen( $this->ipsclass->lang['search_complete'], "autocom=".REGISTRY_URL."&amp;cmd=browse&amp;search=1" );
        }
        else
        {
            // Sorry bud, no results :(
            $this->lib['session']->set_session_var( array( 'search_result' => array() ) );

            $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_search_results' ) );
        }
    }


    /**
     * Build the main menu HTML
     *
     * Present the end-user with the main menu of the garage, does some
     * statistic calculations and renders any of the site_bits enabled
     * in the ACP.
     *
     * @return string Template 'main_menu'
     */
    function main_menu()
    {
        $data = array();

        // Get the total count of items and views in the garage
        $this->ipsclass->DB->query("SELECT count(*) AS total_items, SUM(views) AS total_views FROM ibf_registry_items");
        $row = $this->ipsclass->DB->fetch_row();

        $data['stats']['total_items'] = $row['total_items'];
        $data['stats']['total_views'] = $row['total_views'];

        // Get the total count of mods in the garage
        $this->ipsclass->DB->query("SELECT count(*) AS total_mods FROM ibf_registry_mods");
        $row = $this->ipsclass->DB->fetch_row();

        $data['stats']['total_mods'] = $row['total_mods'];

        // Get the total count of comments in the garage
        $this->ipsclass->DB->query("SELECT count(*) AS total_comments FROM ibf_registry_guestbooks");
        $row = $this->ipsclass->DB->fetch_row();

        $data['stats']['total_comments'] = $row['total_comments'];

        // Do we have a featured item?
        if ( ($this->registry_config['enable_featured_item'] == 1) AND
             ( (empty($this->registry_config['featured_item_id']) === FALSE) OR ($this->registry_config['featured_item_random'] == 1) ) )
        {
            $this->site_bits['featureditem'] = $this->lib['content']->show_featureditem();
        }

        if ( ( $this->ipsclass->check_perms($this->registry_config['browse_perms']) === TRUE ) AND
             ( $this->registry_config['main_browse_on'] == 1 ) )
        {
            // We are passing '1' to bypass and error conditions from halting the script
            $data['browse'] = $this->browse(1);
        }

        // Pass along whether or not the member search is enabled
        $data['main_searchmember_on'] = $this->registry_config['main_searchmember_on'];

        // Return the main menu HTML
        return $this->ipsclass->compiled_templates['skin_registry_main']->main_menu($data);
    }


    /**
     * Build the search menu HTML
     *
     * Present the end-user with the search menu of the registry. This screen
     * is dynamically created based on which fields they have set as searchable.
     *
     * @return string Template 'search_menu'
     */
    function search_menu()
    {
        // Do they have permission?
        if ( $this->ipsclass->check_perms($this->registry_config['interact_perms']) != TRUE )
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'no_permission') );
        }

        // Are we allowed to search?
        if (! $this->ipsclass->vars['allow_search'])
        {
            $this->ipsclass->Error( array( LEVEL => 1, MSG => 'search_off') );
        }

        // Are we really allowed to search?
        if ($this->ipsclass->member['g_use_search'] != 1)
        {
            $this->ipsclass->Error( array( 'LEVEL' => 1, 'MSG' => 'no_permission' ) );
        }

        // Zero out any previous search results
        $this->lib['session']->set_session_var( array( 'search_result' => array() ) );

        // Go get all our custom fields data
        $cf_data = $this->lib['custom_fields']->process_cf( array( 'type' => 'search' ) );

        $cf_special_fields = $this->lib['custom_fields']->process_cf_special_defs( array( 'cf_defs' => $cf_data['cf_defs'] ) );

        // Only add the javscript to the output if they are using the make/model special fields
        if ( in_array( 'make', array_keys($cf_special_fields) ) and in_array( 'model', array_keys($cf_special_fields) ) )
        {
            $data['vehicle_javascript'] = $this->ipsclass->compiled_templates['skin_registry_item']->vehicle_javascript( $this->lib['functions']->build_vehicle_javascript() );

            $data['invoke_vehicle_javascript'] = $this->ipsclass->compiled_templates['skin_registry_item']->invoke_vehicle_javascript( array( 'form' => 'search' ) );
        }

        $data['custom_fields'] = $cf_data['html'];

        // Set page title
        $this->page_title = $this->ipsclass->lang['search'] .' '. $this->ipsclass->lang['title'];

        // Add to our Nav Bar
        $this->nav_bar[] = $this->ipsclass->lang['search'];

        // Return the main menu HTML
        return $this->ipsclass->compiled_templates['skin_registry_main']->search_menu($data);
    }

    /**
     * Build the statistics screen HTML
     *
     * Present the end-user with the statistics of the garage, renders any of
     * the site_bits enabled in the ACP.
     *
     * @return string Template 'stats'
     */
    function stats()
    {
        // Fancy replacement pieces
        $this->site_bits['newestitems']      = $this->lib['content']->show_newestitems();
        $this->site_bits['mostmodded']       = $this->lib['content']->show_mostmodded();
        $this->site_bits['mostviewed']       = $this->lib['content']->show_mostviewed();
        $this->site_bits['newestmods']       = $this->lib['content']->show_newestmods();
        $this->site_bits['lastupdateditems'] = $this->lib['content']->show_lastupdateditems();
        $this->site_bits['lastupdatedmods']  = $this->lib['content']->show_lastupdatedmods();
        $this->site_bits['mostmoneyspent']   = $this->lib['content']->show_mostmoneyspent();
        $this->site_bits['lastcommented']    = $this->lib['content']->show_lastcommented();

        // Set page title
        $this->page_title = $this->ipsclass->lang['title'] .' -> '. $this->ipsclass->lang['stats'];

        // Add to our Nav Bar
        $this->nav_bar[] = $this->ipsclass->lang['stats'];

        // Return the main menu HTML
        return $this->ipsclass->compiled_templates['skin_registry_main']->stats();
    }
}